package com.globopt.global.alg.old;
public class Unirandi {

	private Function fun;
	private double[] x0;
	private double f0;
	private double[] pmin;
	private double[] pmax;
	private double maxfn;
	private double relcon;

	private double[] x;
	private double f;
	private int nfev;

	private double[] xt;
	private double ft;
	private double h;
	private double deltf;

	public Unirandi(Function fun, double[] x0, double f0, double[] pmin, double[] pmax, double maxfn, double relcon) {
		this.fun = fun;
		this.x0 = x0;
		this.f0 = f0;
		this.pmin = pmin;
		this.pmax = pmax;
		this.maxfn = maxfn;
		this.relcon = relcon;
	}

	public void calculate() {
		this.x = x0.clone();
		this.f = f0;
		this.h = 0.001;
		this.deltf = 1.0;
		int itest = 0;
		this.nfev = 0;
		double[][] r = MatlabOperationHelpers.twoDimensionalArraysFillWithRandomNumber(100, fun.nvars);
		int irndm = 0;

		while (nfev < maxfn) {
			irndm++;

			if (irndm >= 100) {
				r = MatlabOperationHelpers.twoDimensionalArraysFillWithRandomNumber(100, fun.nvars);
				irndm = 0;
				continue;
			}
			r[irndm] = MatlabOperationHelpers.vectorAddition(r[irndm], -0.5);
			double a = MatlabOperationHelpers.norm2(r[irndm]);
			// % NEW TRIAL POINT
			r[irndm] = MatlabOperationHelpers.vectorMultiply(1.0 / a, r[irndm]);
			xt = MatlabOperationHelpers.vectorAddition(x, MatlabOperationHelpers.vectorMultiply(h, r[irndm]));
			// % check bounds and enforce them
			int[] ilt = MatlabOperationHelpers.searchIndexLess(xt, -1.0);
			for (int i = 0; i < ilt.length; i++) {
				xt[ilt[i]] = -1.0;
			}
			int[] igt = MatlabOperationHelpers.searchIndexMore(xt, 1.0);
			for (int i = 0; i < igt.length; i++) {
				xt[igt[i]] = 1.0;
			}
			// call fun
			ft = MatlabOperationHelpers.globfun(xt, fun, pmin, pmax);
			nfev++;
			if (ft < f) {
				linsearch(r[irndm]);
				h = Math.abs(h / 2.0);
				continue;
			}
			itest++;
			if (itest < 2) {
				continue;
			}
			// % decrease step length
			h = h / 2.0;
			itest = 0;
			// % relative convergence test for the objective function
			if (deltf < relcon) {
				return;
			}
			// % convergence test for the step length
			if (Math.abs(h) < relcon) {
				return;
			}
		}

	}

	private void linsearch(double[] r) {

		while (ft < f) {
			x = xt.clone();
			deltf = (f - ft) / Math.abs(ft);
			f = ft;
			// % increase step length
			h *= 2.0;
			xt = MatlabOperationHelpers.vectorAddition(x, MatlabOperationHelpers.vectorMultiply(h, r));
			// % check bounds and enforce them
			int[] ilt = MatlabOperationHelpers.searchIndexLess(xt, -1.0);
			for (int i = 0; i < ilt.length; i++) {
				xt[ilt[i]] = -1.0;
			}
			int[] igt = MatlabOperationHelpers.searchIndexMore(xt, 1.0);
			for (int i = 0; i < igt.length; i++) {
				xt[igt[i]] = 1.0;
			}
			// call fun
			ft = MatlabOperationHelpers.globfun(xt, fun, pmin, pmax);
			nfev++;
		}

	}

	public double[] getX() {
		return x;
	}

	public double getF() {
		return f;
	}

	public int getNfev() {
		return nfev;
	}

}
